#include "CSkipListTimerMgr.h"
#include "CTimer.h"
#include "CExecTimerInfoList.h"
#include <string.h>

namespace TB
{
	CSkipListTimerMgr::CSkipListTimerMgr(volatile UINT64* pqwCurTime)
	{
		if (pqwCurTime != nullptr)
			m_pqwCurTime = pqwCurTime;
		m_poTimerMgr = QNEW CObjectResMgr<PTR_OR_VAL(CTimer)>(
			NEW_DELEGATE(
				QPACK(DNewObj<CTimer>),
				this, CSkipListTimerMgr::_NewTimer,
				DELEGATE_PLACEHOLDERS(, std::placeholders::_1)
			)
		);
	}

#ifndef _USING_CLI
	CSkipListTimerMgr::~CSkipListTimerMgr() {
		m_poTimerMgr->ReleaseAll();
		SAFE_DELETE(m_poTimerMgr);
	}
#endif

	CUniquePtr(CTimer) CSkipListTimerMgr::_NewTimer(UINT16)
    {
        CUniquePtr(CTimer) poTimer(QNEW CTimer());
		return poTimer;
    }

	UINT32 CSkipListTimerMgr::Poll(UINT64 qwDeltaMilliSeconds)
	{
		m_qwCurTime += qwDeltaMilliSeconds; // 只设置本地变量，而不设置m_pqwCurTime
		UINT32 dwCount = _ExecTimer(m_dwMaxCountPerPoll);
		return dwCount;
	}

	UINT32 CSkipListTimerMgr::_ExecTimer(UINT32 dwMaxCount)
	{
		UINT32 dwCount = 0;
		while ((dwMaxCount == 0 || dwCount < dwMaxCount) && m_oTimers.GetSize() != 0) {
			auto qwCurTime = GetCurTime();
			auto poNode = m_oTimers.GetFirst();
			if (qwCurTime < poNode->GetKey())
				break;
			auto& roQueue = poNode->GetValue();
			for (; (dwMaxCount == 0 || dwCount < dwMaxCount) && !roQueue.empty(); roQueue.pop_front()) {
				CONST_REF(STimerUID) rsTimerUID = roQueue.at(0);
				PTR(CTimer) poTimer = m_poTimerMgr->GetObj(rsTimerUID.ToUINT64());
				if (poTimer != NULL_PTR) {
					++dwCount;
					if (IS_NOT_NULL_DELEGATE(poTimer->m_cbOnTimer)) {
						poTimer->m_cbOnTimer(rsTimerUID, poTimer->m_dwCurrent, poTimer->m_dwCount);
					}
					if (IsTimerRunning(rsTimerUID)) {
						if (poTimer->m_dwCount == 0 || poTimer->m_dwCurrent < poTimer->m_dwCount - 1) {
							if (poTimer->m_dwCurrent != (UINT32)-1)
								++poTimer->m_dwCurrent;
							UINT64 qwExecTime = 0;
							if (poTimer->m_bAutoFix && poTimer->m_dwCurrent != (UINT32)-1 &&
								((UINT64)-1 - poTimer->m_qwFirstTimeoutTime) / poTimer->m_dwCurrent > poTimer->m_qwIntervalMilliSeconds)
							{
								qwExecTime = poTimer->m_qwFirstTimeoutTime + poTimer->m_qwIntervalMilliSeconds * poTimer->m_dwCurrent;
							}
							else
								qwExecTime = qwCurTime + poTimer->m_qwIntervalMilliSeconds;
							_AddTimer(rsTimerUID, qwExecTime);
						}
						else
							StopTimer(rsTimerUID);
					}
				}
			}
			if (roQueue.empty())
				m_oTimers.Remove(poNode);
		}
		return dwCount;
	}

    STimerUID CSkipListTimerMgr::StartTimer(UINT64 dwMilliSeconds, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		return StartTimer(dwMilliSeconds, 0, dwMilliSeconds, ronTimer, bAutoFix);
    }

    STimerUID CSkipListTimerMgr::StartTimer(UINT64 dwMilliSeconds, UINT32 dwCount, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		return StartTimer(dwMilliSeconds, dwCount, dwMilliSeconds, ronTimer, bAutoFix);
    }

    STimerUID CSkipListTimerMgr::StartTimer(UINT64 dwMilliSeconds, UINT32 dwCount, UINT64 dwFirstTimeoutMilliSeconds, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		auto qwCurTime = GetCurTime();
		PTR(CTimer) poTimer = m_poTimerMgr->CreateObj(0);
		poTimer->m_qwFirstTimeoutTime = qwCurTime + dwFirstTimeoutMilliSeconds;
		poTimer->m_qwIntervalMilliSeconds = dwMilliSeconds;
		poTimer->m_dwCount = dwCount;
		poTimer->m_cbOnTimer = ronTimer;
		poTimer->m_bAutoFix = bAutoFix;
		_AddTimer(poTimer->GetTimerUID(), poTimer->m_qwFirstTimeoutTime);
		return poTimer->GetTimerUID();
    }

    BOOLN CSkipListTimerMgr::IsTimerRunning(CONST_REF(STimerUID) rsTimerUID) QCONST_FUNC
    {
		if (!rsTimerUID)
			return false;
		PTR(CTimer) poTimer = m_poTimerMgr->GetObj(rsTimerUID.ToUINT64());
        return poTimer != NULL_PTR;
    }

    void CSkipListTimerMgr::StopTimer(CONST_REF(STimerUID) rsTimerUID)
    {
        m_poTimerMgr->ReleaseObj(rsTimerUID.ToUINT64());
		// TODO: 如果要从队列里面删除，记得改Poll里面的队列遍历逻辑，以免迭代器失效
    }

	UINT64 CSkipListTimerMgr::GetNextPollTime() const
	{
		auto poFirst = m_oTimers.GetFirst();
		if (poFirst == nullptr)
			return (UINT64)-1;
		return poFirst->GetKey();
	}

	void CSkipListTimerMgr::_AddTimer(CONST_REF(STimerUID) rsTimerUID, UINT64 qwExecTime)
	{
		auto& roQueue = m_oTimers[qwExecTime];
		roQueue.push_back(rsTimerUID);
	}
};
